#ifndef _AGORA_MENU_H
#define _AGORA_MENU_H

#if defined(_WIN32) || defined(_WIN64)
	#include <Windows.h>
	#include <conio.h>
#else
	#include <unistd.h>
	#include <stdlib.h>
	#include <string.h>
#endif

#include <stdio.h>
#include <map>

class Viewer;

#include "Viewer.h"

template <class Class, typename ReturnType, typename ParameterType>
class Menu{
public:
	typedef ReturnType (Class::*Method)( ParameterType );

private:
	Class *c;
	Viewer *v;
	bool b;

	std::map<int, char*> options;
	std::map<int, std::pair<Method, ParameterType> > callbacks;

public:
	Menu(Class* _class, Viewer *_viewer, bool block = true)
	{
		c = _class;
		v = _viewer;
		b = block;

		if(b){
			v->wait();
			v->lock();
		}
	};

	~Menu(){
		if(b) v->unlock();
	}

	void setOptions(std::map<int, char*> opts){
		this->options = opts;
	};

	void setCallbacks(int n, Method m, ParameterType p){
		this->callbacks.insert(std::pair<int, std::pair<Method, ParameterType> >(n, std::pair<Method, ParameterType>(m, p)));
	}

	int show(bool input = true){
		std::map<int, char*>::const_iterator iter;
		for (iter = options.begin(); iter != options.end(); ++iter){
			v->printn("\t%d. %s\n", iter->first, iter->second);
		}

		if(input)
			return v->inputc(false) - '0';
		else
			return -1;
	}

	bool select(int o){
		if(callbacks[o].first != NULL)
		{
			Method m = callbacks[o].first;
			ParameterType p = callbacks[o].second;
			return (c->*m)( p );
		}

		return false;
	}
};

#endif